﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.ComponentModel;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace Pavilion
{
    public class Frame
    {
        public event Action<Frame> SizeChanged;

        public NotifiableCollection<CTexture2D> TextureList { get; private set; }
        public bool EnableLoading { get; set; }
        public float OriginX { get { return origin.X; } set { origin.X = value; } }
        public float OriginY { get { return origin.Y; } set { origin.Y = value; } }
        public Vector2 Origin { get { return origin; } set { origin = value; } }
        public int Width { get; private set; }
        public int Height { get; private set; }

        private Vector2 origin;

        public Frame()
        {
            TextureList = new NotifiableCollection<CTexture2D>();

            TextureList.Added += (CTexture2D texture, int index) =>
            {
                texture.TextureItemChanged += new Action<Texture>(Texture_TextureItemChanged);
                DetermineMaximumDimensions();
            };

            TextureList.Removed += (CTexture2D texture, int index) =>
            {
                texture.TextureItemChanged += new Action<Texture>(Texture_TextureItemChanged);
                DetermineMaximumDimensions();
            };

            EnableLoading = true;
        }

        public Frame(CTexture2D[] textureCollection) : this()
        {
            TextureList.AddRange(textureCollection);
        }

        public Frame Clone()
        {
            Frame frame = new Frame()
            {
                OriginX = this.OriginX,
                OriginY = this.OriginY,
                EnableLoading = this.EnableLoading
            };

            foreach (CTexture2D texture in TextureList)
                frame.TextureList.Add(texture.Clone());

            return frame;
        }

        private void DetermineMaximumDimensions()
        {
            int width = 0;
            int height = 0;

            foreach (CTexture2D texture in TextureList)
            {
                if (width < texture.Width)
                    width = texture.Width;

                if (height < texture.Height)
                    height = texture.Height;
            }

            if (this.Width != width || this.Height != height)
            {
                this.Width = width;
                this.Height = height;
                OnSizeChanged();
            }
        }

        public bool Load(string framePath)
        {
            if (!EnableLoading)
                return false;

            Unload();

            for (int i = 0; i < TextureList.Count; i++)
                TextureList[i].Load(framePath, i.ToString());

            return true;
        }

        public void CreateTexturesFromFolder(string framePath)
        {
            FileInfo[] fileList = new DirectoryInfo(framePath).GetFiles("*.xnb");

            foreach (FileInfo fileInfo in fileList)
            {
                CTexture2D texture = new CTexture2D();
                texture.Load(framePath, fileInfo.Name.Replace(".xnb", ""));
                TextureList.Add(texture);
            }
        }

        public bool Unload()
        {
            if (!EnableLoading)
                return false;

            foreach (CTexture2D texture in TextureList)
                texture.Unload();

            return true;
        }

        public void Draw(Vector2 position)
        {
            this.Draw(position, Color.White, 1f, default(Vector2), SpriteEffects.None);
        }

        public void Draw(Vector2 position, Vector2 origin)
        {
            this.Draw(position, Color.White, 1f, origin, SpriteEffects.None);
        }

        public void Draw(Vector2 position, Color color, float scale, Vector2 origin, SpriteEffects effects)
        {
            Vector2 workingOrigin = DetermineOrigin(effects, origin);

            for (int i = 0; i < TextureList.Count; i++)
                TextureList[i].Draw(position, new Rectangle(0, 0, Width, Height), color, 0f, workingOrigin, scale, effects, 0f);
        }

        public void DrawOnScreen(Vector2 position, Color color, float scale, Vector2 origin, SpriteEffects effects)
        {
            for (int i = 0; i < TextureList.Count; i++)
                TextureList[i].DrawOnScreen(position, new Rectangle(0, 0, Width, Height), color, 0f, origin, scale, effects, 0f);
        }

        public void DrawBoundingBoxOnScreen(Vector2 position, Color outlineColor, float scale, Vector2 origin, SpriteEffects effects)
        {
            Rectangle boundingBox = new Rectangle();

            boundingBox.X = (int)(position.X - (origin.X * scale));
            boundingBox.Y = (int)(position.Y - (origin.Y * scale)) - 1;
            boundingBox.Width = (int)(Width * scale);
            boundingBox.Height = (int)(Height * scale);

            DrawManager.Instance.DrawRectangleOnScreen(boundingBox, outlineColor);
        }

        public Vector2 DetermineOrigin(SpriteEffects effects, Vector2 origin)
        {
            if (effects == SpriteEffects.FlipHorizontally)
                return new Vector2(Width - origin.X, origin.Y);
            else
                return origin;
        }

        private void OnSizeChanged()
        {
            if (SizeChanged != null)
                SizeChanged(this);
        }

        private void Texture_TextureItemChanged(Texture texture)
        {
            DetermineMaximumDimensions();
        }
    }
}
